﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using common4gp;
using System.Diagnostics.Contracts;

namespace wpf4gp.Helpers
{
    /// <summary>
    /// Helper for <see cref="System.Windows.Controls.TreeView"/>
    /// </summary>
    public class TreeViewHelper
    {
        /// <summary>
        /// Gets the selected item of a <see cref="System.Windows.Controls.TreeView"/>
        /// </summary>
        /// <param name="tree">The <see cref="System.Windows.Controls.TreeView"/></param>
        /// <returns>The selected item</returns>
        public static object GetTreeViewSelectedItem(DependencyObject tree)
        {
            Contract.Requires<ArgumentNullException>(tree != null);
            return (object)tree.GetValue(TreeViewSelectedItemProperty);
        }

        /// <summary>
        /// Sets the selected item of a <see cref="System.Windows.Controls.TreeView"/>
        /// </summary>
        /// <param name="tree">The <see cref="System.Windows.Controls.TreeView"/></param>
        /// <param name="value">The selected item</param>
        public static void SetTreeViewSelectedItem(DependencyObject tree, object value)
        {
            Contract.Requires<ArgumentNullException>(tree != null);
            tree.SetValue(TreeViewSelectedItemProperty, value);
        }

        /// <summary>
        /// Dependency for the selected item
        /// </summary>
        public static readonly DependencyProperty TreeViewSelectedItemProperty =
            DependencyProperty.RegisterAttached("TreeViewSelectedItem", 
                                                typeof(object), 
                                                typeof(TreeViewHelper), 
                                                new PropertyMetadata(new object(), 
                                                    TreeViewSelectedItemChanged));

        /// <summary>
        /// Method called when the selected item changes
        /// </summary>
        /// <param name="sender">The tree view</param>
        /// <param name="e">Event args</param>
        static void TreeViewSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            TreeView treeView = sender as TreeView;
            if (treeView.IsNull())
            {
                return;
            }

            treeView.SelectedItemChanged -= new RoutedPropertyChangedEventHandler<object>(treeView_SelectedItemChanged);
            treeView.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(treeView_SelectedItemChanged);

            TreeViewItem thisItem = treeView.ItemContainerGenerator.ContainerFromItem(e.NewValue) as TreeViewItem;
            if (thisItem.IsNotNull())
            {
                thisItem.IsSelected = true;
                return;
            }

            for (int i = 0; i < treeView.Items.Count; i++)
            {
                SelectItem(e.NewValue, treeView.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem);
            }

        }

        /// <summary>
        /// Method called when the selected item changes
        /// </summary>
        /// <param name="sender">The tree view</param>
        /// <param name="e">Event args</param>
        static void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            TreeView treeView = sender as TreeView;
            SetTreeViewSelectedItem(treeView, e.NewValue);
        }


        /// <summary>
        /// Check if a <see cref="System.Windows.Controls.TreeViewItem"/> is the selected one
        /// </summary>
        /// <param name="o">The object to check</param>
        /// <param name="parentItem">The parent item</param>
        /// <returns>Ture if the object is the selected one</returns>
        private static bool SelectItem(object o, TreeViewItem parentItem)
        {
            if (parentItem.IsNull())
            {
                return false;
            }

            bool isExpanded = parentItem.IsExpanded;
            if (!isExpanded)
            {
                parentItem.IsExpanded = true;
                parentItem.UpdateLayout();
            }

            TreeViewItem item = parentItem.ItemContainerGenerator.ContainerFromItem(o) as TreeViewItem;
            if (item.IsNotNull())
            {
                item.IsSelected = true;
                return true;
            }

            bool wasFound = false;
            for (int i = 0; i < parentItem.Items.Count; i++)
            {
                TreeViewItem itm = parentItem.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem;
                var found = SelectItem(o, itm);
                if (!found)
                {
                    itm.IsExpanded = false;
                }
                else
                {
                    wasFound = true;
                }
            }

            return wasFound;
        }
    }
}
